﻿#region License Info

//Component of Cronos Package, http://www.codeplex.com/cronos
//Copyright (C) 2009 Anthony Brockwell

//This program is free software; you can redistribute it and/or
//modify it under the terms of the GNU General Public License
//as published by the Free Software Foundation; either version 2
//of the License, or (at your option) any later version.

//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.

//You should have received a copy of the GNU General Public License
//along with this program; if not, write to the Free Software
//Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

#endregion

using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Windows.Forms;
using ABMath;
using ABMath.ModelFramework.Data;
using ABMath.ModelFramework.Models;
using ABMath.ModelFramework.Transforms;
using ABMath.ModelFramework.Visuals;
using CronosII.Properties;
using ExtraControlLibrary.DirectedGraphs;
using ExtraControlLibrary.VisualControls;
using ICSharpCode.SharpZipLib.GZip;

namespace CronosII
{
    public partial class CronosGUI : Form, IShell
    {
        private static bool hintsOn = true;
        private static int numDrops;
        private DirectedGraph dag;
        private string lastOpenDirectory;

        public CronosGUI(string[] args)
        {
            InitializeComponent();

            dag = new DirectedGraph();
            dagViewer.Graph = dag;
            dagViewer.DAGViewer.NodeSelectEvent += DirectedGraphViewer1NodeSelectEvent;
            LoadSettings(true);

            if (args != null)
                if (args.Length > 0)
                    if (args[0] != null)
                        OpenProjectFile(args[0]);
        }

        private void LoadSettings(bool firstTime)
        {
            hintsOn = Settings.Default.ShowHints;

            dagViewer.DAGViewer.NodeFractionalSize = Settings.Default.WorkspaceNodeSize;
            dagViewer.DAGViewer.MinPixelSize = Settings.Default.WorkspaceMinimumNodePixelSize;
            dagViewer.DAGViewer.RebuildAll(true);

            // load plugins if necessary
            if (firstTime)
               if (Settings.Default.PluginList != null)
                  foreach (var pluginFileName in Settings.Default.PluginList)
                     LoadPlugin(pluginFileName, false);

            dagViewer.Refresh();
        }

        private void CronosGUI_FormClosing(object sender, FormClosingEventArgs e)
        {
            Settings.Default.MaximizeOnStart = (WindowState == FormWindowState.Maximized);
            Settings.Default.Save(); // Important for saving
        }

        /// <summary>
        /// loads from a file (tab or comma separated, two fields per line, first is date/time, second is value)
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void openToolStripMenuItem_Click(object sender, EventArgs e)
        {
            // get the file name
            var opendialog = new OpenFileDialog();
            opendialog.Filter = "Cronos TS Files (*.cts)|*.cts" +
                                "|Delimited Files (*.?sv)|*.?sv" +
                                "|All Files (*.*)|*.*";
            opendialog.CheckFileExists = true;
            opendialog.Multiselect = false; // select multiple files to merge
            if (lastOpenDirectory == null)
                opendialog.InitialDirectory = Settings.Default.DefaultDataDirectory;
            else
                opendialog.InitialDirectory = lastOpenDirectory;

            List<TimeSeries> collection = null;

            if (opendialog.ShowDialog() == DialogResult.OK)
            {
                lastOpenDirectory = Path.GetDirectoryName(opendialog.FileName);
                try
                {
                    if (opendialog.FileName.EndsWith(".zip") || opendialog.FileName.EndsWith(".cts"))
                    {
                        IFormatter formatter = new BinaryFormatter();
                        using (var fs = new FileStream(opendialog.FileName, FileMode.Open))
                        {
                            using (var zipinstream = new GZipInputStream(fs))
                            {
                                var deser = formatter.Deserialize(zipinstream);
                                var ts = deser as TimeSeries;
                                var mts = deser as MVTimeSeries;
                                if (ts != null)
                                {
                                    collection = new List<TimeSeries>();
                                    collection.Add(ts);
                                }
                                else if (mts != null)
                                {
                                    if (mts.Count > 0)
                                        if (mts.Dimension != mts[0].Length)
                                        {
                                            MessageBox.Show(
                                                "Internal file inconsistency, dimension mismatch, attempting to correct ...",
                                                "Warning");
                                            mts.Dimension = mts[0].Length;
                                        }
                                    collection = mts.ExtractList();
                                }
                                else
                                {
                                    throw new Exception("Unrecognized file type.");
                                }
                            }
                        }
                    }
                    else
                    {
                        using (var fs = new FileStream(opendialog.FileName, FileMode.Open, FileAccess.Read,
                                                       FileShare.Read))
                        {
                            try
                            {
                                using (var sreader = new StreamReader(fs))
                                    collection = TimeSeries.GetTSFromReader(sreader, false);
                            }
                            catch (Exception loadException)
                            {
                                if (loadException.Message.Substring(0, 9) == "Duplicate")
                                {
                                    var result = MessageBox.Show(loadException.Message + Environment.NewLine
                                                    + "Try again and ignore duplicates?", "Problem",
                                                    MessageBoxButtons.OKCancel);
                                    if (result == DialogResult.OK)
                                    {
                                        try
                                        {
                                            using (var sreader = new StreamReader(new FileStream(opendialog.FileName, FileMode.Open, FileAccess.Read, FileShare.Read)))
                                                collection = TimeSeries.GetTSFromReader(sreader, true);
                                        }
                                        catch (Exception loadException2)
                                        {
                                            throw loadException2;
                                        }
                                    }
                                }
                                else
                                {
                                    throw loadException;
                                }
                            }
                        }
                    }
                }
                catch (Exception exc)
                {
                    MessageBox.Show("Unable to open file: " + exc.Message, "Error");
                }

                // now we may have one or more time series
                if (collection != null)
                {
                    foreach (TimeSeries ts in collection)
                        ts.RemoveNaNs();
                    DropFromCollection(collection);
                }
            }
        }

        private static void DropNode(ScrollableDAGViewer viewer1, object item)
        {
            if (hintsOn)
            {
                if (numDrops == 0)
                    MessageBox.Show(
                        "You have just created a node.  To place it in the workspace, move the cursor into the workspace and drop it using the left mouse button.",
                        "Tip");
                if (numDrops == 1)
                    MessageBox.Show(
                        "You have created a second node.  After dropping it, to link nodes, right-click on the first node and move the cursor over the second node before releasing.",
                        "Tip");
                ++numDrops;
            }
            viewer1.DAGViewer.DropNode(item);
        }

        /// <summary>
        /// each type of node has a default display
        /// when the node is selected, the display is created
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void DirectedGraphViewer1NodeSelectEvent(object sender, NodeEventArgs e)
        {
            TabPage myTabPage;
            UserControl myUC;

            IConnectable selected = e.nodeList[0].connectableItem;

            switch (GetType(selected))
            {
                case NodeType.MVData:
                    var mvts = selected as MVTimeSeries;
                    // then we should plot it
                    ClearTabPages();

                    myTabPage = new TabPage("(MV) Time Series Plot");
                    var mp = new TSPlotControl(new TSPlotVisual(mvts)) {ShowLag0 = Settings.Default.ACFShowLag0};
                    myUC = mp;
                    myUC.Dock = DockStyle.Fill;
                    myTabPage.Controls.Add(myUC);

                    dynamicTabControl.TabPages.Add(myTabPage);
                    break;


                case NodeType.Data:
                    var ts = selected as TimeSeries;
                    // then we should plot it
                    ClearTabPages();

                    myTabPage = new TabPage("Time Series Plot");
                    var sp = new TSPlotControl(new TSPlotVisual(ts)) {ShowLag0 = Settings.Default.ACFShowLag0};
                    myUC = sp;
                    myUC.Dock = DockStyle.Fill;
                    myTabPage.Controls.Add(myUC);

                    dynamicTabControl.TabPages.Add(myTabPage);
                    break;

                case NodeType.Longitudinal:
                    // we need some way of displaying this
                    MessageBox.Show("Long. data view not yet supported", "Warning");
                    break;

                case NodeType.Transform:
                    //  then we should plot the result of the transformation
                    ClearTabPages();
                    var tf = selected as TimeSeriesTransformation;

                    myTabPage = new TabPage("Transformation");
                    myUC = new TransformationControl(tf, dagViewer.DAGViewer, Settings.Default.ACFShowLag0)
                               {Dock = DockStyle.Fill};
                    myTabPage.Controls.Add(myUC);

                    dynamicTabControl.TabPages.Add(myTabPage);
                    break;

                case NodeType.DataSource:
                    // we treat this like a transform so that parameters can be changed
                    ClearTabPages();
                    var ds = selected as DataSource;

                    myTabPage = new TabPage("Data Source");
                    myUC = new DataSourceControl(ds, dagViewer.DAGViewer, Settings.Default.ACFShowLag0)
                               {Dock = DockStyle.Fill};
                    myTabPage.Controls.Add(myUC);

                    dynamicTabControl.TabPages.Add(myTabPage);
                    break;


                case NodeType.Model:
                    ClearTabPages();
                    var md = selected as Model;

                    myTabPage = new TabPage("Transformed TS Plot");
                    myUC = new ModelControl(md, dagViewer.DAGViewer, this, Settings.Default.ACFShowLag0)
                               {Dock = DockStyle.Fill};
                    myTabPage.Controls.Add(myUC);

                    dynamicTabControl.TabPages.Add(myTabPage);

                    break;

                case NodeType.Visualization:
                    ClearTabPages();
                    
                    // there are several types of visualization
                    UserControl uc = null;
                    var tspv = selected as TSPlotVisual;
                    if (tspv != null)
                        uc = new TSPlotControl(tspv);
                    var ccv = selected as CrossCorrelationVisual;
                    if (ccv != null)
                        uc = new CrossCorrelationControl(ccv);
                    var sav = selected as StrategyAnalysisVisual;
                    if (sav != null)
                        uc = new StrategyAnalysisControl(sav);
                    var rv = selected as ResidualVisual;
                    if (rv != null)
                        uc = new ResidualControl(rv);
                    var sv = selected as SpectralVisual;
                    if (sv != null)
                        uc = new SpectralVisualControl(sv);

                    if (uc != null)
                    {
                        uc.Dock = DockStyle.Fill;
                        myTabPage = new TabPage("Visual");
                        myTabPage.Controls.Add(uc);
                        dynamicTabControl.TabPages.Add(myTabPage);
                    }
                    break;
            }
        }

        /// <summary>
        /// instead of using the Clear method, we use the following function, it disposes of resources
        /// as well as clearing the pages
        /// </summary>
        private void ClearTabPages()
        {
            var pgs = dynamicTabControl.TabPages;
            foreach (TabPage pg in pgs)
            {
                pgs.Remove(pg);
                pg.Dispose();
            }
        }

        private static NodeType GetType(object x)
        {
            if (x as MVTimeSeries != null)
                return NodeType.MVData;
            if (x as TimeSeries != null)
                return NodeType.Data;
            if (x as TimeSeriesTransformation != null)
                return NodeType.Transform;
            if (x as Model != null)
                return NodeType.Model;
            if (x as Visual != null)
                return NodeType.Visualization;
            if (x as Longitudinal != null)
                return NodeType.Longitudinal;
            if (x as DataSource != null)
                return NodeType.DataSource;
            return NodeType.Other;
        }

        private void DropFromCollection(IList<TimeSeries> collection)
        {
            var toAdd = new List<TimeSeries>();
            if (collection.Count > 1)
            {
                var names = new List<string>();
                foreach (TimeSeries ts in collection)
                    names.Add(ts.Title);
                var ms = new MultiSelect(names) {StartPosition = FormStartPosition.CenterParent};
                ms.ShowDialog();
                foreach (int idx in ms.Indices)
                    toAdd.Add(collection[idx]);
            }
            else if (collection.Count == 1)
                toAdd.Add(collection[0]);
            else return;

            if (toAdd.Count > 1)
            {
                var mvts = new MVTimeSeries(toAdd, false) {Title = ("MV(" + toAdd.Count + ")")};
                DropNode(dagViewer, mvts);
            }
            else
                DropNode(dagViewer, toAdd[0]);
            dagViewer.Refresh();
        }

        #region Menu Functions

        private void importFromClipboardToolStripMenuItem_Click(object sender, EventArgs e)
        {
            string imported = Clipboard.GetText();

            if (imported == null)
                return;
            if (imported.Length < 1)
                return;

            var sreader = new StringReader(imported);
            List<TimeSeries> collection;
            try
            {
                collection = TimeSeries.GetTSFromReader(sreader, true);
            }
            catch
            {
                MessageBox.Show("Unable to parse data in clipboard, format may be incorrect.", "Error");
                collection = null;
            }
            if (collection != null)
                DropFromCollection(collection);
        }

        private void fileToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DropNode(dagViewer, new FileDataSource());
        }

        private void subtractTransformToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DropNode(dagViewer, new LinearCombinationTransform());
        }

        private void logReturnTransformToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DropNode(dagViewer, new LogReturnTransformation());
        }

        private void samplerToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            DropNode(dagViewer, new SamplingTransformation());
        }

        private void rotarySwitchToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DropNode(dagViewer, new RotarySwitchTransform());
        }

        private void hubToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DropNode(dagViewer, new HubTransform());
        }

        private void longitudinalSamplerToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            DropNode(dagViewer, new LongitudinalSampler());
        }

        private void samplerButton_Click(object sender, EventArgs e)
        {
            samplerToolStripMenuItem1_Click(sender, e);
        }

        private void hubButton_Click(object sender, EventArgs e)
        {
            hubToolStripMenuItem_Click(sender, e);
        }

        private void rotaryButton_Click(object sender, EventArgs e)
        {
            rotarySwitchToolStripMenuItem_Click(sender, e);
        }

        private void referenceSamplerToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DropNode(dagViewer, new ReferenceSamplingTransform());
        }


        private void customToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DropNode(dagViewer, new CustomTransform());
        }

        private void logTransformToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DropNode(dagViewer, new LogTransform());
        }

        private void mVBindToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DropNode(dagViewer, new BindingTransformation());
        }

        private void crossCorrelationsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DropNode(dagViewer, new CrossCorrelationVisual());
        }

        private void spectralAnalysisToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DropNode(dagViewer, new SpectralVisual());
        }

        private void plotWithACFPACFToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DropNode(dagViewer, new TSPlotVisual());
        }

        private void strategyPLToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DropNode(dagViewer, new StrategyAnalysisVisual());
        }

        private void residualAnalysisToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DropNode(dagViewer, new ResidualVisual());
        }


        private void gARCHToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var orderForm = new OrderSelectForm(1, 0, "Sum-of-Squares Order", "Autoregressive Order")
                                {StartPosition = FormStartPosition.CenterParent};
            if (orderForm.ShowDialog() == DialogResult.OK)
                DropNode(dagViewer, new GARCHModel(GARCHModel.GARCHType.Standard, orderForm.AROrder, orderForm.MAOrder));
        }

        private void aRMAToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var orderForm = new OrderSelectForm(1, 0, "Autoregressive Order", "Moving Average Order")
                                {StartPosition = FormStartPosition.CenterParent};
            if (orderForm.ShowDialog() == DialogResult.OK)
                DropNode(dagViewer, new ARMAModel(orderForm.AROrder, orderForm.MAOrder));
        }

        private void aRMAXToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var orderForm = new OrderSelectForm(1, 0, 1, "Autoregressive Order", "Moving Average Order", "# Exogenous Processes") { StartPosition = FormStartPosition.CenterParent };
            if (orderForm.ShowDialog() == DialogResult.OK)
                DropNode(dagViewer, new ARMAXModel(orderForm.AROrder, orderForm.MAOrder, orderForm.ThirdOrder));
        }


        private void vectorARToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var orderForm = new OrderSelectForm(1, 2, "Autoregressive Order", "Dimension") { StartPosition = FormStartPosition.CenterParent };
            if (orderForm.ShowDialog() == DialogResult.OK)
                DropNode(dagViewer, new VARModel(orderForm.AROrder, orderForm.MAOrder));
        }

        #region Transform Menu Items

        private void differenceToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DropNode(dagViewer, new DifferenceTransformation());
        }

        private void integrateToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DropNode(dagViewer, new IntegrateTransformation());
        }

        private void customToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            DropNode(dagViewer, new FilterTransform());
        }

        private void lagToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DropNode(dagViewer, new LagTransform());
        }

        private void exponentialSmootherToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DropNode(dagViewer, new ExpSmoother());
        }

        private void thresholdToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DropNode(dagViewer, new SaturationTransform());
        }

        private void mVSplitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DropNode(dagViewer, new SplittingTransformation());
        }

        private void mergeToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DropNode(dagViewer, new MergeTransform());
        }

        private void aggregatorToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DropNode(dagViewer, new AggregateTransform());
        }

        private void forecastToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DropNode(dagViewer, new ForecastTransform());
        }

        private void bollingerBandsToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            DropNode(dagViewer, new BollingerBandTransform());
        }

        private void oHLCBuilderToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DropNode(dagViewer, new OHLCBarBuilder());
        }


        private void oHLCAggregatorToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            DropNode(dagViewer, new OHLCAggregator());
        }

        private void midPriceToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DropNode(dagViewer, new MidpointTransformation());
        }

        private void removeOutliersToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DropNode(dagViewer, new PointRemoverTransform());
        }


        #endregion

        private void saveProjectToolStripMenuItem_Click(object sender, EventArgs e)
        {
            // get file name
            var saveDialog = new SaveFileDialog
                                 {
                                     Filter = "Project Files (*.cpj)|*.cpj" + "|All Files (*.*)|*.*"
                                 };

            if (saveDialog.ShowDialog() == DialogResult.OK)
            {
                // store it in a binary file
                using (var zos = new GZipOutputStream(File.Create(saveDialog.FileName)))
                {
                    IFormatter formatter = new BinaryFormatter();
                    formatter.Serialize(zos, dag);
                }
            }
        }

        private void OpenProjectFile(string fileName)
        {
            // load it from a binary file
            using (
                var zos =
                    new GZipInputStream(File.Open(fileName, FileMode.Open, FileAccess.Read,
                                                  FileShare.Read)))
            {
                IFormatter formatter = new BinaryFormatter();
                var newDag = formatter.Deserialize(zos) as DirectedGraph;
                if (newDag == null)
                {
                    // then it failed
                    MessageBox.Show("File format was probably incorrect.", "Open Failure");
                }
                else
                {
                    dag = newDag;
                    dagViewer.Graph = dag;

                    // now go through and recompute everything

                    // Repeat:
                    //    Connect data outputs, or output of any other node whose inputs are all set
                    //    Recompute anything possible
                    //    Until no more changes

                    bool done = false;
                    while (!done)
                    {
                        foreach (DirectedGraph.NodeInfo n in dag.Nodes)
                        {
                            NodeType x = GetType(n.connectableItem);
                            if (x == NodeType.Data || x == NodeType.MVData || x == NodeType.DataSource ||
                                (x == NodeType.Transform && ((TimeSeriesTransformation) n.connectableItem).NumInputs()==0))
                                  dag.CascadeFrom(n); // re-establish all connections
                        }

                        // check to make sure everything is done (fix this!!)
                        done = true;
                    }

                    dagViewer.Refresh();
                }
            }
        }

        private void openProjectToolStripMenuItem_Click(object sender, EventArgs e)
        {
            // get file name
            var openDialog = new OpenFileDialog
                                 {
                                     Filter = "Project Files (*.cpj)|*.cpj" + "|All Files (*.*)|*.*"
                                 };
            if (lastOpenDirectory == null)
                openDialog.InitialDirectory = Settings.Default.DefaultDataDirectory;
            else
                openDialog.InitialDirectory = lastOpenDirectory;

            if (openDialog.ShowDialog() == DialogResult.OK)
            {
                lastOpenDirectory = Path.GetDirectoryName(openDialog.FileName);
                //OpenProjectFile(openDialog.FileName);
                try
                {
                    OpenProjectFile(openDialog.FileName);
                }
                catch
                {
                    MessageBox.Show(
                        "Unable to open file.  It may be an invalid format, or may include objects that require additional plugins.",
                        "Error");
                }
            }
        }

        private void clearCurrentProjectToolStripMenuItem_Click(object sender, EventArgs e)
        {
            dag = new DirectedGraph();
            dagViewer.DAGViewer.Graph = dag;
            dagViewer.Refresh();
        }

        private void aboutToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            var aform = new AboutForm();
            aform.StartPosition = FormStartPosition.CenterParent;
            aform.ShowDialog();
        }

        private void preferencesToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var sf = new SettingsForm(Settings.Default) {StartPosition = FormStartPosition.CenterParent};
            if (sf.ShowDialog() == DialogResult.OK)
                LoadSettings(false);
        }

        #endregion

        #region Plugin Handling

        private readonly List<IPlugin> pluginList = new List<IPlugin>();
        private readonly List<CronosPluginType> pluginTypeList = new List<CronosPluginType>();

        public void DropIntoWorkspace(object o)
        {
            DropNode(dagViewer, o);
        }

        private void loadPluginToolStripMenuItem_Click(object sender, EventArgs e)
        {
            // get the file name
            var opendialog = new OpenFileDialog();

            opendialog.InitialDirectory = Path.GetDirectoryName(Application.ExecutablePath);
            opendialog.Filter = "dll Files (*.dll)|*.dll" +
                                "|All Files (*.*)|*.*";
            opendialog.CheckFileExists = true;
            opendialog.Multiselect = false; // select multiple files to merge

            if (opendialog.ShowDialog() == DialogResult.OK)
                LoadPlugin(opendialog.FileName, true);
        }

        private void LoadPlugin(string fileName, bool showMessages)
        {
            int initialCount = pluginList.Count;

            Assembly assembly = Assembly.LoadFile(fileName);
            Type[] typeList = assembly.GetTypes();
            foreach (Type tp in typeList)
            {
                object[] attributes = tp.GetCustomAttributes(false);
                foreach (object z in attributes)
                {
                    var zcpa = z as CronosPluginAttribute;
                    if (zcpa != null)
                    {
                        object plugin = Activator.CreateInstance(tp);
                        var ipl = plugin as IPlugin;
                        pluginList.Add(ipl);
                        pluginTypeList.Add(zcpa.Type);
                    }
                }
            }

            if (pluginList.Count > initialCount) // i.e. we found at least one new thing
            {
                ToolStripDropDown modelDropDown = null;
                ToolStripDropDown transformDropDown = null;
                ToolStripDropDown sourcesDropDown = null;
                ToolStripDropDown visualsDropDown = null;

                var modelMenu = menuStrip1.Items[4] as ToolStripDropDownItem; // model menu
                if (modelMenu != null)
                    modelDropDown = modelMenu.DropDown;
                var visualsMenu = menuStrip1.Items[3] as ToolStripDropDownItem;
                if (visualsMenu != null)
                    visualsDropDown = visualsMenu.DropDown;
                var transformMenu = menuStrip1.Items[2] as ToolStripDropDownItem;
                if (transformMenu != null)
                    transformDropDown = transformMenu.DropDown;
                var sourcesMenu = menuStrip1.Items[1] as ToolStripDropDownItem;
                if (sourcesMenu != null)
                    sourcesDropDown = sourcesMenu.DropDown;

                for (int i = initialCount; i < pluginList.Count; ++i)
                {
                    switch (pluginTypeList[i])
                    {
                        case CronosPluginType.Model:
                            pluginList[i].Initialize(modelDropDown, this);
                            break;
                        case CronosPluginType.Transform:
                            pluginList[i].Initialize(transformDropDown, this);
                            break;
                        case CronosPluginType.Visualization:
                            pluginList[i].Initialize(visualsDropDown, this);
                            break;
                        case CronosPluginType.Source:
                            pluginList[i].Initialize(sourcesDropDown, this);
                            break;
                        default:
                            throw new ApplicationException("Only model and transform plugins supported for now.");
                    }
                }

                int numAdded = pluginList.Count - initialCount;
                if (showMessages)
                   MessageBox.Show(numAdded + " plugin item(s) loaded.", "Plugins");
            }
            else
                if (showMessages)
                    MessageBox.Show("No compatible plugins found in this dll file.", "Error");
        }

        #endregion

        #region Nested type: NodeType

        private enum NodeType
        {
            Data,
            Transform,
            Model,
            MVData,
            Other,
            Visualization,
            Longitudinal,
            DataSource
        } ;

        #endregion

    }
}
